import random
import time
import PySimpleGUI as sg
import matplotlib.pyplot as plt
import numpy as np
from math import *

sg.theme('DarkAmber')  # 设置当前主题
# 界面布局，将会按照列表顺序从上往下依次排列，二级列表中，从左往右依此排列
layout = [[sg.Frame(layout=[
              [sg.Text('仿真周期'), sg.InputText(size=(10,1)),sg.Text('仿真长度'), sg.InputText(size=(10,1)),
               sg.Text('调度步长'), sg.InputText(size=(10,1)),sg.Text('目标速度'), sg.InputText(size=(10,1))],
              [sg.Text('目标方向'), sg.InputText(size=(10,1)),sg.Text('目标优先级'), sg.InputText(size=(10,1)),
               sg.Text('目标到达时间'), sg.InputText(size=(10,1)),sg.Text('目标期望执行时间'), sg.InputText(size=(10,1))],
              [sg.Checkbox('HPEDF', size=(10,1)),  sg.Checkbox('二次优先级分配算法', default=True),
               sg.Radio('对地模式', "RADIO1", default=True, size=(10,1)), sg.Radio('对空模式', "RADIO1")]],
              title='资源调度基础设置',title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='Use these to set flags')],
          [sg.Frame(layout=[
              [sg.Button('参数设置'), sg.Button('初始化'), sg.Button('仿真启动'),
               sg.Button('仿真停止'), sg.Button('性能分析'), sg.Button('CANCEL')],
              [sg.Checkbox('有时间窗自适应调度算法', size=(20,1)),  sg.Checkbox('无时间窗自适应调度算法', default=True)],
              [sg.Checkbox('先来先服务算法（FCFS）', size=(20,1)),  sg.Checkbox('短作业优先算法（SJF）', size=(20,1)),
               sg.Checkbox('高响应比优先算法（HRRN）', default=True)]],
              title='操作控制',title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='Use these to set flags')],
          [sg.Frame(layout=[
              [sg.Text('工作频率/GHz'), sg.InputText(size=(10, 1)), sg.Text('信号带宽/MHz'), sg.InputText(size=(10, 1)),
               sg.Text('天线增益/dB'), sg.InputText(size=(10, 1)), sg.Text('噪声系数/dB'), sg.InputText(size=(10, 1))],
              [sg.Text('测速精度/(m/s)'), sg.InputText(size=(10, 1)), sg.Text('测距精度/m'), sg.InputText(size=(10, 1)),
               sg.Text('方位向扫描范围/deg'), sg.InputText(size=(10, 1))],
              [sg.Text('俯仰向扫描范围/deg'), sg.InputText(size=(10, 1)), sg.Text('最大作用距离/m'), sg.InputText(size=(10, 1)),
               sg.Text('脉冲重复周期/μs'), sg.InputText(size=(10, 1))],
              [sg.Text('方位向波束宽度/deg'), sg.InputText(size=(10, 1)), sg.Text('俯仰向波束宽度/deg'), sg.InputText(size=(10, 1))],
              [sg.Text('脉冲积累数'), sg.InputText(size=(10, 1)), sg.Text('脉冲宽度/μs'), sg.InputText(size=(10, 1))]],
              title='参数设置——搜索参数',title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='Use these to set flags')],
          [sg.Frame(layout=[
              [sg.Text('工作频率/GHz'), sg.InputText(size=(10, 1)), sg.Text('信号带宽/MHz'), sg.InputText(size=(10, 1)),
               sg.Text('天线增益/dB'), sg.InputText(size=(10, 1)), sg.Text('噪声系数/dB'), sg.InputText(size=(10, 1))],
              [sg.Text('测速精度/(m/s)'), sg.InputText(size=(10, 1)), sg.Text('测距精度/m'), sg.InputText(size=(10, 1)),
               sg.Text('精密跟踪采样间隔/s'), sg.InputText(size=(10, 1))],
              [sg.Text('中优先级采样间隔/s'), sg.InputText(size=(10, 1)), sg.Text('普通跟踪采样间隔/s'), sg.InputText(size=(10, 1)),
               sg.Text('脉冲重复周期/μs'), sg.InputText(size=(10, 1))],
              [sg.Text('方位向波束宽度/deg'), sg.InputText(size=(10, 1)), sg.Text('俯仰向波束宽度/deg'), sg.InputText(size=(10, 1))],
              [sg.Text('脉冲积累数'), sg.InputText(size=(10, 1)), sg.Text('脉冲宽度/μs'), sg.InputText(size=(10, 1))]],
              title='参数设置——跟踪参数',title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='Use these to set flags')],
          [sg.Frame(layout=[
              [sg.Text('地面目标个数'), sg.InputText(size=(10, 1)), sg.Text('低空目标个数'), sg.InputText(size=(10, 1)),
               sg.Text('地面目标检测概率'), sg.InputText(size=(10, 1))],
              [sg.Text('空中目标检测概率'), sg.InputText(size=(10, 1)), sg.Text('目标分布直径/km'), sg.InputText(size=(10, 1))]],
              title='参数设置——目标参数',title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='Use these to set flags')],
          [sg.Frame(layout=[
              [sg.Text('载机个数'), sg.InputText(size=(10, 1)), sg.Text('飞行轨迹'), sg.InputText(size=(10, 1)),
               sg.Text('飞行速度/(m/s)'), sg.InputText(size=(10, 1)), sg.Text('加速度/(m/s^2)'), sg.InputText(size=(10, 1))]],
              title='参数设置——载机参数',title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='Use these to set flags')],
          [sg.Frame(layout=[
              [sg.Text('发射功率/w'), sg.InputText(size=(10, 1)), sg.Text('平均功率/w'), sg.InputText(size=(10, 1))]],
              title='参数设置——雷达参数',title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='Use these to set flags')],
          [sg.Button('OK')]]

text = sg.popup_get_file('基于本地端已有文件的输入')

# 创造窗口
window = sg.Window('相控阵雷达资源调度相关算法仿真平台', layout)
# 事件循环并获取输入值
while True:
    event, values = window.read()
    if event in (None, 'OK', 'CANCEL'):  # 如果用户关闭窗口或点击`Ok`/'CANCEL'
        break
    if event in ('参数设置'):
        sg.popup('参数开始设置')
    if event in ('初始化', '仿真启动', '性能分析'):
        sg.popup('进程已开始')
    if event in ('仿真停止'):
        sg.popup('进程已终止')

window.close()

class PCB:
    def __init__(self, pid, priority, arr_time, all_time, cpu_time, start_block, block_time, state):  ##初始化进程
        self.pid = pid
        self.priority = priority
        self.arr_time = arr_time
        self.all_time = all_time
        self.cpu_time = cpu_time
        self.start_block = start_block
        self.block_time = block_time
        self.state = state

    def output(self):  ##hrrn输出
        print("进程" + str(self.pid), "优先级：" + str(self.priority), "到达时间:" + str(self.arr_time),
              "还需运行时间:" + str(self.all_time), "已运行时间:" + str(self.cpu_time),
              "开始阻塞时间：" + str(self.start_block), "阻塞时间：" + str(self.block_time), "状态：" + self.state)

    def Output(self):  ##sjf fcfs输出
        print("进程" + str(self.pid), "正在执行，到达时间:" + str(self.arr_time),
              "还需运行时间:" + str(self.all_time), "已运行时间:" + str(self.cpu_time))

    def toBlock(self):  ##将状态置为Block
        self.state = "Block"

    def toRun(self):  ##将状态置为Run
        self.state = "Run"

    def toFinish(self):  ##将状态置为Finish
        self.state = "Finish"

    def toReady(self):  ##将状态置为Ready
        self.state = "Ready"

    def running(self):  ##进程运行时状态变化
        self.all_time -= 1
        self.cpu_time += 1

    def toBlocking(self):  ##进程将要开始阻塞的状态变化
        if self.start_block > 0:
            self.start_block -= 1

    def blocking(self):  ##进程阻塞时的状态变化
        if self.block_time > 0:
            self.block_time -= 1
        self.priority += 1


def init(num):  ##初始化进程，生成四个进程并按到达时间将它们放入列表list1

    while 1:
        list1 = []
        for i in range(num): #修改生成进程数目
            list1.append(PCB(str(i), random.randint(1, 10), random.randint(10, 15),
                         random.randint(1, 10), 0, random.randint(5, 10), random.randint(1, 10), "Ready"))
        for i in range(len(list1) - 1):
            for j in range(i + 1, len(list1)):
                if list1[i].arr_time > list1[j].arr_time:
                    list1[i], list1[j] = list1[j], list1[i]
        return list1


def fcfs(list1):  ##先来先服务
    time = 0
    while 1:
        print("time:", time)
        if time >= list1[0].arr_time:
            list1[0].running()
            list1[0].Output()
            if list1[0].all_time == 0:
                print("进程" + list1[0].pid + "执行完毕,周转时间：" + str(time - list1[0].arr_time + 1) + "\n")
                list1.remove(list1[0])
        time += 1
        if not list1:
            break


def sjf(list1):  ##抢占式短作业优先
    list2 = []  ##就绪队列
    time = 0
    while 1:
        len_list2 = len(list2)
        print("time:", time)
        if list1:
            i = 0
            while 1:  ##将进程放入就绪队列，就绪队列的第一个是正在执行的进程
                if time == list1[i].arr_time:
                    list2.append(list1[i])
                    list1.remove(list1[i])
                    pid = list2[0].pid  ##获取就绪队列第一个进程的进程ID
                    i -= 1
                i += 1
                if i >= len(list1):
                    break
        if len(list2) >= 2 and len(list2) != len_list2:  ##判断就绪队列中最短的作业
            len_list2 = len(list2)
            for i in range(len(list2) - 1):
                for j in range(i + 1, len(list2)):
                    if list2[i].all_time > list2[j].all_time:
                        list2[i], list2[j] = list2[j], list2[i]
        if list2:  ##执行过程
            if pid != list2[0].pid:  ##如果正在执行的进程改变，则发生抢占
                print("发生抢占，进程" + list2[0].pid + "开始执行")
                pid = list2[0].pid
            list2[0].running()
            list2[0].Output()
            if list2[0].all_time == 0:
                print("进程" + list2[0].pid + "执行完毕,周转时间：" + str(time - list2[0].arr_time + 1) + "\n")
                list2.remove(list2[0])
                if list2:
                    pid = list2[0].pid
        time += 1
        if not list2 and not list1:
            break


def hrrn(list1):  ##动态最高优先数优先
    list2 = []  ##就绪队列
    list3 = []  ##阻塞队列
    time = 0
    while 1:
        print("time:", time)
        if list1:
            i = 0
            while 1:  ##将进程放入就绪队列
                if time == list1[i].arr_time:
                    list2.append(list1[i])
                    list1.remove(list1[i])
                    pid = list2[0].pid
                    i -= 1
                i += 1
                if i >= len(list1):
                    break
        for i in range(len(list2) - 1):  ##将就绪队列的进程按优先级大小排列
            for j in range(i + 1, len(list2)):
                if list2[i].priority < list2[j].priority:
                    list2[i].toReady()
                    list2[i], list2[j] = list2[j], list2[i]
        if list2:  ##执行过程
            if pid != list2[0].pid:
                print("发生抢占，进程" + list2[0].pid + "开始执行")

                pid = list2[0].pid
            if list2[0].start_block > 0 or list2[0].block_time <= 0:
                list2[0].toRun()
                list2[0].running()
                list2[0].toBlocking()
            for i in range(1, len(list2)):
                list2[i].priority += 1
                list2[i].toBlocking()
        if list3:  ##阻塞队列
            for i in list3:
                i.blocking()

        for i in list2:
            i.output()
        for i in list3:
            i.output()

        if list2:  ##当进程开始阻塞时间为0，将进程放入阻塞队列
            i = 0
            while 1:
                if list2:
                    if list2[i].start_block == 0 and list2[i].block_time != 0:
                        print("进程" + list2[i].pid + "开始阻塞，进入阻塞队列")
                        list2[i].toBlock()
                        list3.append(list2[i])
                        list2.remove(list2[i])
                        i -= 1
                i += 1
                if i >= len(list2):
                    break

        if list3:  ##当进程阻塞时间为0，将进程放入就绪队列
            i = 0
            while 1:
                if list3[i].block_time == 0:
                    print("进程" + list3[i].pid + "阻塞结束，进入就绪队列")

                    list3[i].toReady()
                    list2.append(list3[i])
                    list3.remove(list3[i])
                    pid = list2[0].pid
                    i -= 1
                i += 1
                if i >= len(list3):
                    break

        if list2:  ##进程执行完毕则移出就绪队列
            if list2[0].all_time <= 0:
                list2[0].toFinish()
                print("进程" + list2[0].pid + "执行完毕，周转时间：" + str(time - list2[0].arr_time + 1),
                      "状态：" + list2[0].state + "\n")
                print("时间利用率：" + str((time - list2[0].arr_time + 1) / time))

                plt.ion()  # 开启interactive mode 成功的关键函数
                plt.figure(1)
                t = [0]
                t_now = (time - list2[0].arr_time + 1) / time
                m = [t_now]
                for i in range(2):

                    t_now = (time - list2[0].arr_time + 1) / time
                    plt.plot(list2[0].pid, t_now, '.')

                    plt.plot(t, m, '-r')
                    plt.pause(0.01)

                list2.remove(list2[0])
                if list2:
                    pid = list2[0].pid

        time += 1
        if not (list1 or list2 or list3):
            break


if __name__ == "__main__":
    while 1:
        n = input("请选择算法(1、先来先服务  2、抢占式短作业优先  3、高响应比优先):")
        if n == "1":
            list1 = init(4)
            for i in list1:
                i.Output()
            fcfs(list1)
        elif n == "2":
            list1 = init(4)
            for i in list1:
                i.Output()
            sjf(list1)
        elif n == "3":
            list1 = init(40)
            for i in list1:
                i.output()
            hrrn(list1)
            import sys

            app = QtWidgets.QApplication(sys.argv)
            mainWindow = QtWidgets.QMainWindow()
            ui = Ui_mainWindow()
            ui.setupUi(mainWindow)
            mainWindow.show()
            sys.exit(app.exec_())
            exit(0)
        else:
            print("输入错误，请重新输入！")
